package com.daikun.common.utils;

import cn.hutool.extra.spring.SpringUtil;
import com.daikun.common.enums.BaseResultEnum;
import com.daikun.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

/**
 * redis 锁工具类
 * @author bojue created 2025-07-10
 * @version 0.0.1 init
 */
@Slf4j
public class BaseLockUtil {

    private static final RedissonClient redissonClient;

    static {
        redissonClient = SpringUtil.getBean(RedissonClient.class);
        if (redissonClient == null) {
            throw new BizException(BaseResultEnum.SYSTEM_ERROR, "当前工程未配置 redis 链接信息");
        }
    }

    /**
     * 等待获取锁，获取不到就一直等，获取后不释放，会一直持有
     * @param lockKey 锁 key
     */
    public static RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 等待获取锁，获取后，等待指定时间后自动释放锁
     * @param lockKey 锁 key
     * @param timeout 锁持有的时长，默认单位 秒
     */
    public static RLock lock(String lockKey, long timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    /**
     * 等待获取锁，获取后，等待指定时间后自动释放锁
     * @param lockKey 锁 key
     * @param unit 时长单位
     * @param timeout 持有锁的时长
     */
    public static RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    /**
     * 尝试加锁，获取不到锁，马上返回
     * @param lockKey 锁 key
     * @return 加锁失败返回 false，加锁成功返回 true
     */
    public static boolean tryLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock();
        } catch (Exception e) {
            log.info("LockUtil.tryLock fail -> lockKey = {}, msg = {}", lockKey, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 尝试加锁，获取不到锁，马上返回
     * @param lockKey 锁 key
     * @return 加锁失败返回 false，加锁成功返回 true
     */
    public static boolean tryLock(String lockKey, long timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(timeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.info("LockUtil.tryLock fail -> lockKey = {}, msg = {}", lockKey, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 尝试加锁，获取不到就等一段时间，超时返回 false
     * @param lockKey 锁 key
     * @param unit 等待时间单位
     * @param waitTime 等待时长
     * @param leaseTime 持有时长，超过这个时间，会自动释放锁
     */
    public static boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (Exception e) {
            log.info("LockUtil.tryLock fail -> lockKey = {}, unit = {}, waitTime = {}, leaseTime = {}, msg = {}",
                    lockKey, unit, waitTime, leaseTime, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 释放锁
     * @param lockKey 锁 key
     */
    public static void unLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock.isHeldByCurrentThread() && lock.isLocked()) {
            lock.unlock();
        }
    }

    /**
     * 释放锁
     * @param lock 加锁时返回的锁对象
     */
    public static void unLock(RLock lock) {
        if (lock.isHeldByCurrentThread() && lock.isLocked()) {
            lock.unlock();
        }
    }

}
